package edu.ynu.se.xiecheng.achitectureclass.project.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ynu.se.xiecheng.achitectureclass.project.entity.Token;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.*;

@Service
public class TokenService {
    private static final Logger logger = LoggerFactory.getLogger(TokenService.class);
    private final Map<String, Token> tokenCache = new HashMap<>(); // 缓存两种 Token

    @Autowired
    private RestTemplate restTemplate;

    @PostConstruct
    public void init() {
        TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
        logger.info("Default TimeZone set to: {}", TimeZone.getDefault().getID());

        initializeToken("soil");
        initializeToken("camera");
    }

    private void initializeToken(String type) {
        Token token = loadTokenFromLocal(type);
        if (token != null && !isTokenExpired(token)) {
            tokenCache.put(type, token);
            logger.info("{} token loaded from local file and is still valid.", type);
        } else {
            logger.info("No valid {} token found in local file, refreshing token.", type);
            refreshToken(type);
        }
    }

    public String getSoilToken() {
        return getToken("soil");
    }

    public String getCameraToken() {
        return getToken("camera");
    }

    public String getToken(String type) {
        Token token = tokenCache.get(type);
        if (token == null || isTokenExpired(token)) {
            logger.info("Token for {} is expired or not found, refreshing...", type);
            refreshToken(type);
            token = tokenCache.get(type);
        }
        return token.getAccessToken();
    }

    private boolean isTokenExpired(Token token) {
        return token.getExpireTime().before(new Date());
    }

    public void refreshToken(String type) {
        String accessToken;
        Date expireTime;

        if ("soil".equals(type)) {
            accessToken = fetchSoilToken();
            expireTime = calculateExpireTime(2);
        } else if ("camera".equals(type)) {
            // 获取 camera token 的 Map 数据
            Map<String, Object> tokenData = fetchCameraToken();
            accessToken = (String) tokenData.get("accessToken");
            long expireTimeMillis = (Long) tokenData.get("expireTime"); // 获取 expireTime 的时间戳
            expireTime = new Date(expireTimeMillis); // 将时间戳转换为 Date
        } else {
            throw new IllegalArgumentException("Invalid token type: " + type);
        }

        // 创建并保存 Token 对象
        Token token = new Token();
        token.setAccessToken(accessToken);
        token.setExpireTime(expireTime);
        token.setType(type);
        tokenCache.put(type, token);

        // 保存到本地文件
        saveTokenToLocal(type, token);
        logger.info("Token refreshed and saved for type: {}", type);
    }

    private String fetchSoilToken() {
        String url = "https://fbox360.com/idserver/core/connect/token";
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("scope", "fbox");
        params.add("client_id", "68db2e8bda8d47b5b5db7eaf71c7dcdd");
        params.add("client_secret", "76dc724c95004acab25482d344dab407");
        params.add("grant_type", "client_credentials");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
        ResponseEntity<Map> response = restTemplate.postForEntity(url, request, Map.class);

        if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
            return (String) response.getBody().get("access_token");
        } else {
            logger.error("Failed to fetch soil token: {}", response.getStatusCode());
            throw new RuntimeException("Failed to fetch soil token");
        }
    }

    private Map<String, Object> fetchCameraToken() {
        String url = "http://42.193.14.241:7000/ysapi/subAccount/getToken";

        // 构建请求体
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("accountId", "1ca7f0ab24ba41b291346347ec30140e");

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 发送请求
        HttpEntity<Map<String, String>> request = new HttpEntity<>(requestBody, headers);
        ResponseEntity<Map> response = restTemplate.postForEntity(url, request, Map.class);

        // 错误处理
        if (response.getStatusCode() != HttpStatus.OK) {
            throw new RuntimeException("Failed to fetch token: " + response.getBody());
        }

        // 解析响应
        Map<String, Object> responseBody = response.getBody();
        if (responseBody == null) {
            throw new RuntimeException("Response body is null");
        }

        // 检查 code 字段
        String code = (String) responseBody.get("code");
        if (!"200".equals(code)) {
            throw new RuntimeException("Failed to fetch token: " + responseBody.get("msg"));
        }

        // 提取 data 字段
        Map<String, Object> data = (Map<String, Object>) responseBody.get("data");
        if (data == null) {
            throw new RuntimeException("Data field is null");
        }

        // 提取 accessToken 和 expireTime
        String accessToken = (String) data.get("accessToken");
        Long expireTime = (Long) data.get("expireTime"); // 注意类型是 Long
        if (accessToken == null || expireTime == null) {
            throw new RuntimeException("Access token or expire time is null");
        }

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", accessToken);
        result.put("expireTime", expireTime);
        return result;
    }

    private Date calculateExpireTime(int hours) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.HOUR_OF_DAY, hours);
        return calendar.getTime();
    }

    private void saveTokenToLocal(String type, Token token) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            File file = new File(type + "-token.json");
            objectMapper.writeValue(file, token);
            logger.info("Token saved to local file: {}", file.getAbsolutePath());
        } catch (IOException e) {
            logger.error("Failed to save token to local file: {}", e.getMessage());
            throw new RuntimeException("Failed to save token to local file", e);
        }
    }

    private Token loadTokenFromLocal(String type) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            File file = new File(type + "-token.json");
            if (file.exists()) {
                Token token = objectMapper.readValue(file, Token.class);
                logger.info("Token loaded from local file: {}", file.getAbsolutePath());
                return token;
            } else {
                logger.info("No token file found: {}", file.getAbsolutePath());
                return null;
            }
        } catch (IOException e) {
            logger.error("Failed to load token from local file: {}", e.getMessage());
            return null;
        }
    }
}